home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / EasyPHP-2.0b1-setup.exe / {app} / phpmyadmin / libraries / sqlparser.lib.php < prev    next >
Encoding:
PHP Script  |  2006-11-18  |  92.3 KB  |  2,354 lines

  1. <?php
  2. /* $Id: sqlparser.lib.php 9317 2006-08-16 17:42:01Z lem9 $ */
  3. // vim: expandtab sw=4 ts=4 sts=4:
  4.  
  5. /** SQL Parser Functions for phpMyAdmin
  6.  *
  7.  * Copyright 2002 Robin Johnson <robbat2@users.sourceforge.net>
  8.  * http://www.orbis-terrarum.net/?l=people.robbat2
  9.  *
  10.  * These functions define an SQL parser system, capable of understanding and
  11.  * extracting data from a MySQL type SQL query.
  12.  *
  13.  * The basic procedure for using the new SQL parser:
  14.  * On any page that needs to extract data from a query or to pretty-print a
  15.  * query, you need code like this up at the top:
  16.  *
  17.  * ($sql contains the query)
  18.  * $parsed_sql = PMA_SQP_parse($sql);
  19.  *
  20.  * If you want to extract data from it then, you just need to run
  21.  * $sql_info = PMA_SQP_analyze($parsed_sql);
  22.  *
  23.  * lem9: See comments in PMA_SQP_analyze for the returned info
  24.  *       from the analyzer.
  25.  *
  26.  * If you want a pretty-printed version of the query, do:
  27.  * $string = PMA_SQP_formatHtml($parsed_sql);
  28.  * (note that that you need to have syntax.css.php included somehow in your
  29.  * page for it to work, I recommend '<link rel="stylesheet" type="text/css"
  30.  * href="syntax.css.php" />' at the moment.)
  31.  */
  32.  
  33.  
  34. /**
  35.  * Minimum inclusion? (i.e. for the stylesheet builder)
  36.  */
  37. if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) {
  38.     /**
  39.      * Include the string library as we use it heavily
  40.      */
  41.     require_once('./libraries/string.lib.php');
  42.  
  43.     /**
  44.      * Include data for the SQL Parser
  45.      */
  46.     require_once('./libraries/sqlparser.data.php');
  47.     require_once('./libraries/mysql_charsets.lib.php');
  48.     if (!isset($mysql_charsets)) {
  49.         $mysql_charsets = array();
  50.         $mysql_charsets_count = 0;
  51.         $mysql_collations_flat = array();
  52.         $mysql_collations_count = 0;
  53.     }
  54.  
  55.     if (!defined('DEBUG_TIMING')) {
  56.         function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize)
  57.         {
  58.             $arr[] = array('type' => $type, 'data' => $data);
  59.             $arrsize++;
  60.         } // end of the "PMA_SQP_arrayAdd()" function
  61.     } else {
  62.         function PMA_SQP_arrayAdd(&$arr, $type, $data, &$arrsize)
  63.         {
  64.             global $timer;
  65.  
  66.             $t     = $timer;
  67.             $arr[] = array('type' => $type, 'data' => $data, 'time' => $t);
  68.             $timer = microtime();
  69.             $arrsize++;
  70.         } // end of the "PMA_SQP_arrayAdd()" function
  71.     } // end if... else...
  72.  
  73.  
  74.     /**
  75.      * Reset the error variable for the SQL parser
  76.      *
  77.      * @access public
  78.      */
  79.     // Added, Robbat2 - 13 Janurary 2003, 2:59PM
  80.     function PMA_SQP_resetError()
  81.     {
  82.         global $SQP_errorString;
  83.         $SQP_errorString = '';
  84.         unset($SQP_errorString);
  85.     }
  86.  
  87.     /**
  88.      * Get the contents of the error variable for the SQL parser
  89.      *
  90.      * @return string Error string from SQL parser
  91.      *
  92.      * @access public
  93.      */
  94.     // Added, Robbat2 - 13 Janurary 2003, 2:59PM
  95.     function PMA_SQP_getErrorString()
  96.     {
  97.         global $SQP_errorString;
  98.         return isset($SQP_errorString) ? $SQP_errorString : '';
  99.     }
  100.  
  101.     /**
  102.      * Check if the SQL parser hit an error
  103.      *
  104.      * @return boolean error state
  105.      *
  106.      * @access public
  107.      */
  108.     // Added, Robbat2 - 13 Janurary 2003, 2:59PM
  109.     function PMA_SQP_isError()
  110.     {
  111.         global $SQP_errorString;
  112.         return isset($SQP_errorString) && !empty($SQP_errorString);
  113.     }
  114.  
  115.     /**
  116.      * Set an error message for the system
  117.      *
  118.      * @param  string  The error message
  119.      * @param  string  The failing SQL query
  120.      *
  121.      * @access private
  122.      * @scope SQL Parser internal
  123.      */
  124.     // Revised, Robbat2 - 13 Janurary 2003, 2:59PM
  125.     function PMA_SQP_throwError($message, $sql)
  126.     {
  127.  
  128.         global $SQP_errorString;
  129.         $SQP_errorString = '<p>'.$GLOBALS['strSQLParserUserError'] . '</p>' . "\n"
  130.             . '<pre>' . "\n"
  131.             . 'ERROR: ' . $message . "\n"
  132.             . 'SQL: ' . htmlspecialchars($sql) .  "\n"
  133.             . '</pre>' . "\n";
  134.  
  135.     } // end of the "PMA_SQP_throwError()" function
  136.  
  137.  
  138.     /**
  139.      * Do display the bug report
  140.      *
  141.      * @param  string  The error message
  142.      * @param  string  The failing SQL query
  143.      *
  144.      * @access public
  145.      */
  146.     function PMA_SQP_bug($message, $sql)
  147.     {
  148.         global $SQP_errorString;
  149.         $debugstr = 'ERROR: ' . $message . "\n";
  150.         $debugstr .= 'CVS: $Id: sqlparser.lib.php 9317 2006-08-16 17:42:01Z lem9 $' . "\n";
  151.         $debugstr .= 'MySQL: '.PMA_MYSQL_STR_VERSION . "\n";
  152.         $debugstr .= 'USR OS, AGENT, VER: ' . PMA_USR_OS . ' ' . PMA_USR_BROWSER_AGENT . ' ' . PMA_USR_BROWSER_VER . "\n";
  153.         $debugstr .= 'PMA: ' . PMA_VERSION . "\n";
  154.         $debugstr .= 'PHP VER,OS: ' . PMA_PHP_STR_VERSION . ' ' . PHP_OS . "\n";
  155.         $debugstr .= 'LANG: ' . $GLOBALS['lang'] . "\n";
  156.         $debugstr .= 'SQL: ' . htmlspecialchars($sql);
  157.  
  158.         $encodedstr     = $debugstr;
  159.         if (@function_exists('gzcompress')) {
  160.             $encodedstr = gzcompress($debugstr, 9);
  161.         }
  162.         $encodedstr     = preg_replace("/(\015\012)|(\015)|(\012)/", '<br />' . "\n", chunk_split(base64_encode($encodedstr)));
  163.  
  164.         $SQP_errorString .= $GLOBALS['strSQLParserBugMessage'] . '<br />' . "\n"
  165.              . '----' . $GLOBALS['strBeginCut'] . '----' . '<br />' . "\n"
  166.              . $encodedstr . "\n"
  167.              . '----' . $GLOBALS['strEndCut'] . '----' . '<br />' . "\n";
  168.  
  169.         $SQP_errorString .= '----' . $GLOBALS['strBeginRaw'] . '----<br />' . "\n"
  170.              . '<pre>' . "\n"
  171.              . $debugstr
  172.              . '</pre>' . "\n"
  173.              . '----' . $GLOBALS['strEndRaw'] . '----<br />' . "\n";
  174.  
  175.     } // end of the "PMA_SQP_bug()" function
  176.  
  177.  
  178.     /**
  179.      * Parses the SQL queries
  180.      *
  181.      * @param  string   The SQL query list
  182.      *
  183.      * @return mixed    Most of times, nothing...
  184.      *
  185.      * @global array    The current PMA configuration
  186.      * @global array    MySQL column attributes
  187.      * @global array    MySQL reserved words
  188.      * @global array    MySQL column types
  189.      * @global array    MySQL function names
  190.      * @global integer  MySQL column attributes count
  191.      * @global integer  MySQL reserved words count
  192.      * @global integer  MySQL column types count
  193.      * @global integer  MySQL function names count
  194.      * @global array    List of available character sets
  195.      * @global array    List of available collations
  196.      * @global integer  Character sets count
  197.      * @global integer  Collations count
  198.      *
  199.      * @access public
  200.      */
  201.     function PMA_SQP_parse($sql)
  202.     {
  203.         global $cfg;
  204.         global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type, $PMA_SQPdata_function_name,
  205.                $PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt;
  206.         global $mysql_charsets, $mysql_collations_flat, $mysql_charsets_count, $mysql_collations_count;
  207.         global $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt;
  208.  
  209.         // rabus: Convert all line feeds to Unix style
  210.         $sql = str_replace("\r\n", "\n", $sql);
  211.         $sql = str_replace("\r", "\n", $sql);
  212.  
  213.         $len = PMA_strlen($sql);
  214.         if ($len == 0) {
  215.             return array();
  216.         }
  217.  
  218.         $sql_array               = array();
  219.         $sql_array['raw']        = $sql;
  220.         $count1                  = 0;
  221.         $count2                  = 0;
  222.         $punct_queryend          = ';';
  223.         $punct_qualifier         = '.';
  224.         $punct_listsep           = ',';
  225.         $punct_level_plus        = '(';
  226.         $punct_level_minus       = ')';
  227.         $digit_floatdecimal      = '.';
  228.         $digit_hexset            = 'x';
  229.         $bracket_list            = '()[]{}';
  230.         $allpunct_list           =  '-,;:!?/.^~\*&%+<=>|';
  231.         $allpunct_list_pair      = array (
  232.             0 => '!=',
  233.             1 => '&&',
  234.             2 => ':=',
  235.             3 => '<<',
  236.             4 => '<=',
  237.             5 => '<=>',
  238.             6 => '<>',
  239.             7 => '>=',
  240.             8 => '>>',
  241.             9 => '||'
  242.         );
  243.         $allpunct_list_pair_size = 10; //count($allpunct_list_pair);
  244.         $quote_list              = '\'"`';
  245.         $arraysize               = 0;
  246.  
  247.         while ($count2 < $len) {
  248.             $c      = PMA_substr($sql, $count2, 1);
  249.             $count1 = $count2;
  250.  
  251.             if (($c == "\n")) {
  252.                 $count2++;
  253.                 PMA_SQP_arrayAdd($sql_array, 'white_newline', '', $arraysize);
  254.                 continue;
  255.             }
  256.  
  257.             // Checks for white space
  258.             if (PMA_STR_isSpace($c)) {
  259.                 $count2++;
  260.                 continue;
  261.             }
  262.  
  263.             // Checks for comment lines.
  264.             // MySQL style #
  265.             // C style /* */
  266.             // ANSI style --
  267.             if (($c == '#')
  268.                 || (($count2 + 1 < $len) && ($c == '/') && (PMA_substr($sql, $count2 + 1, 1) == '*'))
  269.                 || (($count2 + 2 == $len) && ($c == '-') && (PMA_substr($sql, $count2 + 1, 1) == '-'))
  270.                 || (($count2 + 2 < $len) && ($c == '-') && (PMA_substr($sql, $count2 + 1, 1) == '-') && ((PMA_substr($sql, $count2 + 2, 1) <= ' ')))) {
  271.                 $count2++;
  272.                 $pos  = 0;
  273.                 $type = 'bad';
  274.                 switch ($c) {
  275.                     case '#':
  276.                         $type = 'mysql';
  277.                     case '-':
  278.                         $type = 'ansi';
  279.                         $pos  = $GLOBALS['PMA_strpos']($sql, "\n", $count2);
  280.                         break;
  281.                     case '/':
  282.                         $type = 'c';
  283.                         $pos  = $GLOBALS['PMA_strpos']($sql, '*/', $count2);
  284.                         $pos  += 2;
  285.                         break;
  286.                     default:
  287.                         break;
  288.                 } // end switch
  289.                 $count2 = ($pos < $count2) ? $len : $pos;
  290.                 $str    = PMA_substr($sql, $count1, $count2 - $count1);
  291.                 PMA_SQP_arrayAdd($sql_array, 'comment_' . $type, $str, $arraysize);
  292.                 continue;
  293.             } // end if
  294.  
  295.             // Checks for something inside quotation marks
  296.             if (PMA_STR_strInStr($c, $quote_list)) {
  297.                 $startquotepos   = $count2;
  298.                 $quotetype       = $c;
  299.                 $count2++;
  300.                 $escaped         = FALSE;
  301.                 $escaped_escaped = FALSE;
  302.                 $pos             = $count2;
  303.                 $oldpos          = 0;
  304.                 do {
  305.                     $oldpos = $pos;
  306.                     $pos    = $GLOBALS['PMA_strpos'](' ' . $sql, $quotetype, $oldpos + 1) - 1;
  307.                     // ($pos === FALSE)
  308.                     if ($pos < 0) {
  309.                         $debugstr = $GLOBALS['strSQPBugUnclosedQuote'] . ' @ ' . $startquotepos. "\n"
  310.                                   . 'STR: ' . htmlspecialchars($quotetype);
  311.                         PMA_SQP_throwError($debugstr, $sql);
  312.                         return $sql;
  313.                     }
  314.  
  315.                     // If the quote is the first character, it can't be
  316.                     // escaped, so don't do the rest of the code
  317.                     if ($pos == 0) {
  318.                         break;
  319.                     }
  320.  
  321.                     // Checks for MySQL escaping using a \
  322.                     // And checks for ANSI escaping using the $quotetype character
  323.                     if (($pos < $len) && PMA_STR_charIsEscaped($sql, $pos)) {
  324.                         $pos ++;
  325.                         continue;
  326.                     } elseif (($pos + 1 < $len) && (PMA_substr($sql, $pos, 1) == $quotetype) && (PMA_substr($sql, $pos + 1, 1) == $quotetype)) {
  327.                         $pos = $pos + 2;
  328.                         continue;
  329.                     } else {
  330.                         break;
  331.                     }
  332.                 } while ($len > $pos); // end do
  333.  
  334.                 $count2       = $pos;
  335.                 $count2++;
  336.                 $type         = 'quote_';
  337.                 switch ($quotetype) {
  338.                     case '\'':
  339.                         $type .= 'single';
  340.                         break;
  341.                     case '"':
  342.                         $type .= 'double';
  343.                         break;
  344.                     case '`':
  345.                         $type .= 'backtick';
  346.                         break;
  347.                     default:
  348.                         break;
  349.                 } // end switch
  350.                 $data = PMA_substr($sql, $count1, $count2 - $count1);
  351.                 PMA_SQP_arrayAdd($sql_array, $type, $data, $arraysize);
  352.                 continue;
  353.             }
  354.  
  355.             // Checks for brackets
  356.             if (PMA_STR_strInStr($c, $bracket_list)) {
  357.                 // All bracket tokens are only one item long
  358.                 $count2++;
  359.                 $type_type     = '';
  360.                 if (PMA_STR_strInStr($c, '([{')) {
  361.                     $type_type = 'open';
  362.                 } else {
  363.                     $type_type = 'close';
  364.                 }
  365.  
  366.                 $type_style     = '';
  367.                 if (PMA_STR_strInStr($c, '()')) {
  368.                     $type_style = 'round';
  369.                 } elseif (PMA_STR_strInStr($c, '[]')) {
  370.                     $type_style = 'square';
  371.                 } else {
  372.                     $type_style = 'curly';
  373.                 }
  374.  
  375.                 $type = 'punct_bracket_' . $type_type . '_' . $type_style;
  376.                 PMA_SQP_arrayAdd($sql_array, $type, $c, $arraysize);
  377.                 continue;
  378.             }
  379.  
  380.             // Checks for identifier (alpha or numeric)
  381.             if (PMA_STR_isSqlIdentifier($c, FALSE) || ($c == '@') || ($c == '.' && PMA_STR_isDigit(PMA_substr($sql, $count2 + 1, 1)))) {
  382.                 $count2 ++;
  383.  
  384.                 //TODO: a @ can also be present in expressions like
  385.                 // FROM 'user'@'%'
  386.                 // or  TO 'user'@'%'
  387.                 // in this case, the @ is wrongly marked as alpha_variable
  388.  
  389.                 $is_sql_variable         = ($c == '@');
  390.                 $is_digit                = (!$is_sql_variable) && PMA_STR_isDigit($c);
  391.                 $is_hex_digit            = ($is_digit) && ($c == '.') && ($c == '0') && ($count2 < $len) && (PMA_substr($sql, $count2, 1) == 'x');
  392.                 $is_float_digit          = $c == '.';
  393.                 $is_float_digit_exponent = FALSE;
  394.  
  395.                 // Nijel: Fast skip is especially needed for huge BLOB data, requires PHP at least 4.3.0:
  396.                 if (PMA_PHP_INT_VERSION >= 40300) {
  397.                     if ($is_hex_digit) {
  398.                         $count2++;
  399.                         $pos = strspn($sql, '0123456789abcdefABCDEF', $count2);
  400.                         if ($pos > $count2) {
  401.                             $count2 = $pos;
  402.                         }
  403.                         unset($pos);
  404.                     } elseif ($is_digit) {
  405.                         $pos = strspn($sql, '0123456789', $count2);
  406.                         if ($pos > $count2) {
  407.                             $count2 = $pos;
  408.                         }
  409.                         unset($pos);
  410.                     }
  411.                 }
  412.  
  413.                 while (($count2 < $len) && PMA_STR_isSqlIdentifier(PMA_substr($sql, $count2, 1), ($is_sql_variable || $is_digit))) {
  414.                     $c2 = PMA_substr($sql, $count2, 1);
  415.                     if ($is_sql_variable && ($c2 == '.')) {
  416.                         $count2++;
  417.                         continue;
  418.                     }
  419.                     if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) {
  420.                         $count2++;
  421.                         if (!$is_float_digit) {
  422.                             $is_float_digit = TRUE;
  423.                             continue;
  424.                         } else {
  425.                             $debugstr = $GLOBALS['strSQPBugInvalidIdentifer'] . ' @ ' . ($count1+1) . "\n"
  426.                                       . 'STR: ' . htmlspecialchars(PMA_substr($sql, $count1, $count2 - $count1));
  427.                             PMA_SQP_throwError($debugstr, $sql);
  428.                             return $sql;
  429.                         }
  430.                     }
  431.                     if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) {
  432.                         if (!$is_float_digit_exponent) {
  433.                             $is_float_digit_exponent = TRUE;
  434.                             $is_float_digit          = TRUE;
  435.                             $count2++;
  436.                             continue;
  437.                         } else {
  438.                             $is_digit                = FALSE;
  439.                             $is_float_digit          = FALSE;
  440.                         }
  441.                     }
  442.                     if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && PMA_STR_isDigit($c2))) {
  443.                         $count2++;
  444.                         continue;
  445.                     } else {
  446.                         $is_digit     = FALSE;
  447.                         $is_hex_digit = FALSE;
  448.                     }
  449.  
  450.                     $count2++;
  451.                 } // end while
  452.  
  453.                 $l    = $count2 - $count1;
  454.                 $str  = PMA_substr($sql, $count1, $l);
  455.  
  456.                 $type = '';
  457.                 if ($is_digit) {
  458.                     $type     = 'digit';
  459.                     if ($is_float_digit) {
  460.                         $type .= '_float';
  461.                     } elseif ($is_hex_digit) {
  462.                         $type .= '_hex';
  463.                     } else {
  464.                         $type .= '_integer';
  465.                     }
  466.                 } else {
  467.                     if ($is_sql_variable != FALSE) {
  468.                         $type = 'alpha_variable';
  469.                     } else {
  470.                         $type = 'alpha';
  471.                     }
  472.                 } // end if... else....
  473.                 PMA_SQP_arrayAdd($sql_array, $type, $str, $arraysize);
  474.  
  475.                 continue;
  476.             }
  477.  
  478.             // Checks for punct
  479.             if (PMA_STR_strInStr($c, $allpunct_list)) {
  480.                 while (($count2 < $len) && PMA_STR_strInStr(PMA_substr($sql, $count2, 1), $allpunct_list)) {
  481.                     $count2++;
  482.                 }
  483.                 $l = $count2 - $count1;
  484.                 if ($l == 1) {
  485.                     $punct_data = $c;
  486.                 } else {
  487.                     $punct_data = PMA_substr($sql, $count1, $l);
  488.                 }
  489.  
  490.                 // Special case, sometimes, althought two characters are
  491.                 // adjectent directly, they ACTUALLY need to be seperate
  492.                 if ($l == 1) {
  493.                     $t_suffix         = '';
  494.                     switch ($punct_data) {
  495.                         case $punct_queryend:
  496.                             $t_suffix = '_queryend';
  497.                             break;
  498.                         case $punct_qualifier:
  499.                             $t_suffix = '_qualifier';
  500.                             break;
  501.                         case $punct_listsep:
  502.                             $t_suffix = '_listsep';
  503.                             break;
  504.                         default:
  505.                             break;
  506.                     }
  507.                     PMA_SQP_arrayAdd($sql_array, 'punct' . $t_suffix, $punct_data, $arraysize);
  508.                 } elseif (PMA_STR_binarySearchInArr($punct_data, $allpunct_list_pair, $allpunct_list_pair_size)) {
  509.                     // Ok, we have one of the valid combined punct expressions
  510.                     PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize);
  511.                 } else {
  512.                     // Bad luck, lets split it up more
  513.                     $first  = $punct_data[0];
  514.                     $first2 = $punct_data[0] . $punct_data[1];
  515.                     $last2  = $punct_data[$l - 2] . $punct_data[$l - 1];
  516.                     $last   = $punct_data[$l - 1];
  517.                     if (($first == ',') || ($first == ';') || ($first == '.') || ($first == '*')) {
  518.                         $count2     = $count1 + 1;
  519.                         $punct_data = $first;
  520.                     } elseif (($last2 == '/*') || (($last2 == '--') && ($count2 == $len || PMA_substr($sql, $count2, 1) <= ' ') )) {
  521.                         $count2     -= 2;
  522.                         $punct_data = PMA_substr($sql, $count1, $count2 - $count1);
  523.                     } elseif (($last == '-') || ($last == '+') || ($last == '!')) {
  524.                         $count2--;
  525.                         $punct_data = PMA_substr($sql, $count1, $count2 - $count1);
  526.                     // TODO: for negation operator, split in 2 tokens ?
  527.                     // "select x&~1 from t"
  528.                     // becomes "select x & ~ 1 from t" ?
  529.  
  530.                     } elseif ($last != '~') {
  531.                         $debugstr =  $GLOBALS['strSQPBugUnknownPunctuation'] . ' @ ' . ($count1+1) . "\n"
  532.                                   . 'STR: ' . htmlspecialchars($punct_data);
  533.                         PMA_SQP_throwError($debugstr, $sql);
  534.                         return $sql;
  535.                     }
  536.                     PMA_SQP_arrayAdd($sql_array, 'punct', $punct_data, $arraysize);
  537.                     continue;
  538.                 } // end if... elseif... else
  539.                 continue;
  540.             }
  541.  
  542.             // DEBUG
  543.             $count2++;
  544.  
  545.             $debugstr = 'C1 C2 LEN: ' . $count1 . ' ' . $count2 . ' ' . $len .  "\n"
  546.                       . 'STR: ' . PMA_substr($sql, $count1, $count2 - $count1) . "\n";
  547.             PMA_SQP_bug($debugstr, $sql);
  548.             return $sql;
  549.  
  550.         } // end while ($count2 < $len)
  551.  
  552.  
  553.         if ($arraysize > 0) {
  554.             $t_next           = $sql_array[0]['type'];
  555.             $t_prev           = '';
  556.             $t_bef_prev       = '';
  557.             $t_cur            = '';
  558.             $d_next           = $sql_array[0]['data'];
  559.             $d_prev           = '';
  560.             $d_bef_prev       = '';
  561.             $d_cur            = '';
  562.             $d_next_upper     = $t_next == 'alpha' ? strtoupper($d_next) : $d_next;
  563.             $d_prev_upper     = '';
  564.             $d_bef_prev_upper = '';
  565.             $d_cur_upper      = '';
  566.         }
  567.  
  568.         for ($i = 0; $i < $arraysize; $i++) {
  569.             $t_bef_prev       = $t_prev;
  570.             $t_prev           = $t_cur;
  571.             $t_cur            = $t_next;
  572.             $d_bef_prev       = $d_prev;
  573.             $d_prev           = $d_cur;
  574.             $d_cur            = $d_next;
  575.             $d_bef_prev_upper = $d_prev_upper;
  576.             $d_prev_upper     = $d_cur_upper;
  577.             $d_cur_upper      = $d_next_upper;
  578.             if (($i + 1) < $arraysize) {
  579.                 $t_next = $sql_array[$i + 1]['type'];
  580.                 $d_next = $sql_array[$i + 1]['data'];
  581.                 $d_next_upper = $t_next == 'alpha' ? strtoupper($d_next) : $d_next;
  582.             } else {
  583.                 $t_next       = '';
  584.                 $d_next       = '';
  585.                 $d_next_upper = '';
  586.             }
  587.  
  588.             //DEBUG echo "[prev: <b>".$d_prev."</b> ".$t_prev."][cur: <b>".$d_cur."</b> ".$t_cur."][next: <b>".$d_next."</b> ".$t_next."]<br />";
  589.  
  590.             if ($t_cur == 'alpha') {
  591.                 $t_suffix     = '_identifier';
  592.                 if (($t_next == 'punct_qualifier') || ($t_prev == 'punct_qualifier')) {
  593.                     $t_suffix = '_identifier';
  594.                 } elseif (($t_next == 'punct_bracket_open_round')
  595.                   && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_function_name, $PMA_SQPdata_function_name_cnt)) {
  596.                     // FIXME-2005-10-16: in the case of a CREATE TABLE containing a TIMESTAMP,
  597.                     // since TIMESTAMP() is also a function, it's found here and
  598.                     // the token is wrongly marked as alpha_functionName. But we
  599.                     // compensate for this when analysing for timestamp_not_null
  600.                     // later in this script.
  601.                     $t_suffix = '_functionName';
  602.                 } elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_type, $PMA_SQPdata_column_type_cnt)) {
  603.                     $t_suffix = '_columnType';
  604.  
  605.                     // Temporary fix for BUG #621357
  606.                     //TODO FIX PROPERLY NEEDS OVERHAUL OF SQL TOKENIZER
  607.                     if ($d_cur_upper == 'SET' && $t_next != 'punct_bracket_open_round') {
  608.                         $t_suffix = '_reservedWord';
  609.                     }
  610.                     //END OF TEMPORARY FIX
  611.  
  612.                     // CHARACTER is a synonym for CHAR, but can also be meant as
  613.                     // CHARACTER SET. In this case, we have a reserved word.
  614.                     if ($d_cur_upper == 'CHARACTER' && $d_next_upper == 'SET') {
  615.                         $t_suffix = '_reservedWord';
  616.                     }
  617.  
  618.                     // experimental
  619.                     // current is a column type, so previous must not be
  620.                     // a reserved word but an identifier
  621.                     // CREATE TABLE SG_Persons (first varchar(64))
  622.  
  623.                     //if ($sql_array[$i-1]['type'] =='alpha_reservedWord') {
  624.                     //    $sql_array[$i-1]['type'] = 'alpha_identifier';
  625.                     //}
  626.  
  627.                 } elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_reserved_word, $PMA_SQPdata_reserved_word_cnt)) {
  628.                     $t_suffix = '_reservedWord';
  629.                 } elseif (PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_column_attrib, $PMA_SQPdata_column_attrib_cnt)) {
  630.                     $t_suffix = '_columnAttrib';
  631.                     // INNODB is a MySQL table type, but in "SHOW INNODB STATUS",
  632.                     // it should be regarded as a reserved word.
  633.                     if ($d_cur_upper == 'INNODB' && $d_prev_upper == 'SHOW' && $d_next_upper == 'STATUS') {
  634.                         $t_suffix = '_reservedWord';
  635.                     }
  636.  
  637.                     if ($d_cur_upper == 'DEFAULT' && $d_next_upper == 'CHARACTER') {
  638.                         $t_suffix = '_reservedWord';
  639.                     }
  640.                     // Binary as character set
  641.                     if ($d_cur_upper == 'BINARY' && (
  642.                       ($d_bef_prev_upper == 'CHARACTER' && $d_prev_upper == 'SET')
  643.                       || ($d_bef_prev_upper == 'SET' && $d_prev_upper == '=')
  644.                       || ($d_bef_prev_upper == 'CHARSET' && $d_prev_upper == '=')
  645.                       || $d_prev_upper == 'CHARSET'
  646.                       ) && PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, count($mysql_charsets))) {
  647.                         $t_suffix = '_charset';
  648.                     }
  649.                 } elseif (PMA_STR_binarySearchInArr($d_cur, $mysql_charsets, $mysql_charsets_count)
  650.                   || PMA_STR_binarySearchInArr($d_cur, $mysql_collations_flat, $mysql_collations_count)
  651.                   || ($d_cur{0} == '_' && PMA_STR_binarySearchInArr(substr($d_cur, 1), $mysql_charsets, $mysql_charsets_count))) {
  652.                     $t_suffix = '_charset';
  653.                 } else {
  654.                     // Do nothing
  655.                 }
  656.                 // check if present in the list of forbidden words
  657.                 if ($t_suffix == '_reservedWord' && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt)) {
  658.                     $sql_array[$i]['forbidden'] = TRUE;
  659.                 } else {
  660.                     $sql_array[$i]['forbidden'] = FALSE;
  661.                 }
  662.                 $sql_array[$i]['type'] .= $t_suffix;
  663.             }
  664.         } // end for
  665.  
  666.         // Stores the size of the array inside the array, as count() is a slow
  667.         // operation.
  668.         $sql_array['len'] = $arraysize;
  669.  
  670.         // Sends the data back
  671.         return $sql_array;
  672.     } // end of the "PMA_SQP_parse()" function
  673.  
  674.    /**
  675.     * Checks for token types being what we want...
  676.     *
  677.     * @param  string String of type that we have
  678.     * @param  string String of type that we want
  679.     *
  680.     * @return boolean result of check
  681.     *
  682.     * @access private
  683.     */
  684.     function PMA_SQP_typeCheck($toCheck, $whatWeWant)
  685.     {
  686.         $typeSeperator = '_';
  687.         if (strcmp($whatWeWant, $toCheck) == 0) {
  688.             return TRUE;
  689.         } else {
  690.             if (strpos($whatWeWant, $typeSeperator) === FALSE) {
  691.                 return strncmp($whatWeWant, $toCheck, strpos($toCheck, $typeSeperator)) == 0;
  692.             } else {
  693.                 return FALSE;
  694.             }
  695.         }
  696.     }
  697.  
  698.  
  699.     /**
  700.      * Analyzes SQL queries
  701.      *
  702.      * @param  array   The SQL queries
  703.      *
  704.      * @return array   The analyzed SQL queries
  705.      *
  706.      * @access public
  707.      */
  708.     function PMA_SQP_analyze($arr)
  709.     {
  710.         if ($arr == array()) {
  711.             return array();
  712.         }
  713.         $result          = array();
  714.         $size            = $arr['len'];
  715.         $subresult       = array(
  716.             'querytype'      => '',
  717.             'select_expr_clause'=> '', // the whole stuff between SELECT and FROM , except DISTINCT
  718.             'position_of_first_select' => '', // the array index
  719.             'from_clause'=> '',
  720.             'group_by_clause'=> '',
  721.             'order_by_clause'=> '',
  722.             'having_clause'  => '',
  723.             'where_clause'   => '',
  724.             'where_clause_identifiers'   => array(),
  725.             'unsorted_query' => '',
  726.             'queryflags'     => array(),
  727.             'select_expr'    => array(),
  728.             'table_ref'      => array(),
  729.             'foreign_keys'   => array(),
  730.             'create_table_fields' => array()
  731.         );
  732.         $subresult_empty = $subresult;
  733.         $seek_queryend         = FALSE;
  734.         $seen_end_of_table_ref = FALSE;
  735.         $number_of_brackets_in_extract = 0;
  736.         $number_of_brackets_in_group_concat = 0;
  737.  
  738.         // for SELECT EXTRACT(YEAR_MONTH FROM CURDATE())
  739.         // we must not use CURDATE as a table_ref
  740.         // so we track wether we are in the EXTRACT()
  741.         $in_extract          = FALSE;
  742.  
  743.         // for GROUP_CONCAT( ... )
  744.         $in_group_concat     = FALSE;
  745.  
  746. /* Description of analyzer results by lem9
  747.  *
  748.  * db, table, column, alias
  749.  * ------------------------
  750.  *
  751.  * Inside the $subresult array, we create ['select_expr'] and ['table_ref'] arrays.
  752.  *
  753.  * The SELECT syntax (simplified) is
  754.  *
  755.  * SELECT
  756.  *    select_expression,...
  757.  *    [FROM [table_references]
  758.  *
  759.  *
  760.  * ['select_expr'] is filled with each expression, the key represents the
  761.  * expression position in the list (0-based) (so we don't lose track of
  762.  * multiple occurences of the same column).
  763.  *
  764.  * ['table_ref'] is filled with each table ref, same thing for the key.
  765.  *
  766.  * I create all sub-values empty, even if they are
  767.  * not present (for example no select_expression alias).
  768.  *
  769.  * There is a debug section at the end of loop #1, if you want to
  770.  * see the exact contents of select_expr and table_ref
  771.  *
  772.  * queryflags
  773.  * ----------
  774.  *
  775.  * In $subresult, array 'queryflags' is filled, according to what we
  776.  * find in the query.
  777.  *
  778.  * Currently, those are generated:
  779.  *
  780.  * ['queryflags']['need_confirm'] = 1; if the query needs confirmation
  781.  * ['queryflags']['select_from'] = 1;  if this is a real SELECT...FROM
  782.  * ['queryflags']['distinct'] = 1;     for a DISTINCT
  783.  * ['queryflags']['union'] = 1;        for a UNION
  784.  * ['queryflags']['join'] = 1;         for a JOIN
  785.  * ['queryflags']['offset'] = 1;       for the presence of OFFSET
  786.  *
  787.  * query clauses
  788.  * -------------
  789.  *
  790.  * The select is splitted in those clauses:
  791.  * ['select_expr_clause']
  792.  * ['from_clause']
  793.  * ['group_by_clause']
  794.  * ['order_by_clause']
  795.  * ['having_clause']
  796.  * ['where_clause']
  797.  *
  798.  * The identifiers of the WHERE clause are put into the array
  799.  * ['where_clause_identifier']
  800.  *
  801.  * For a SELECT, the whole query without the ORDER BY clause is put into
  802.  * ['unsorted_query']
  803.  *
  804.  * foreign keys
  805.  * ------------
  806.  * The CREATE TABLE may contain FOREIGN KEY clauses, so they get
  807.  * analyzed and ['foreign_keys'] is an array filled with
  808.  * the constraint name, the index list,
  809.  * the REFERENCES table name and REFERENCES index list,
  810.  * and ON UPDATE | ON DELETE clauses
  811.  *
  812.  * position_of_first_select
  813.  * ------------------------
  814.  *
  815.  * The array index of the first SELECT we find. Will be used to
  816.  * insert a SQL_CALC_FOUND_ROWS.
  817.  *
  818.  * create_table_fields
  819.  * -------------------
  820.  *
  821.  * For now, mostly used to detect the DEFAULT CURRENT_TIMESTAMP and
  822.  * ON UPDATE CURRENT_TIMESTAMP clauses of the CREATE TABLE query.
  823.  * An array, each element is the identifier name.
  824.  * Note that for now, the timestamp_not_null element is created
  825.  * even for non-TIMESTAMP fields.
  826.  *
  827.  * Sub-elements: ['type'] which contains the column type
  828.  *               optional (currently they are never false but can be absent):
  829.  *               ['default_current_timestamp'] boolean
  830.  *               ['on_update_current_timestamp'] boolean
  831.  *               ['timestamp_not_null'] boolean
  832.  *
  833.  * section_before_limit, section_after_limit
  834.  * -----------------------------------------
  835.  *
  836.  * Marks the point of the query where we can insert a LIMIT clause;
  837.  * so the section_before_limit will contain the left part before
  838.  * a possible LIMIT clause
  839.  *
  840.  *
  841.  * End of description of analyzer results
  842.  */
  843.  
  844.         // must be sorted
  845.         // TODO: current logic checks for only one word, so I put only the
  846.         // first word of the reserved expressions that end a table ref;
  847.         // maybe this is not ok (the first word might mean something else)
  848. //        $words_ending_table_ref = array(
  849. //            'FOR UPDATE',
  850. //            'GROUP BY',
  851. //            'HAVING',
  852. //            'LIMIT',
  853. //            'LOCK IN SHARE MODE',
  854. //            'ORDER BY',
  855. //            'PROCEDURE',
  856. //            'UNION',
  857. //            'WHERE'
  858. //        );
  859.         $words_ending_table_ref = array(
  860.             'FOR',
  861.             'GROUP',
  862.             'HAVING',
  863.             'LIMIT',
  864.             'LOCK',
  865.             'ORDER',
  866.             'PROCEDURE',
  867.             'UNION',
  868.             'WHERE'
  869.         );
  870.         $words_ending_table_ref_cnt = 9; //count($words_ending_table_ref);
  871.  
  872.         $words_ending_clauses = array(
  873.             'FOR',
  874.             'LIMIT',
  875.             'LOCK',
  876.             'PROCEDURE',
  877.             'UNION'
  878.         );
  879.         $words_ending_clauses_cnt = 5; //count($words_ending_clauses);
  880.  
  881.  
  882.  
  883.  
  884.         // must be sorted
  885.         $supported_query_types = array(
  886.             'SELECT'
  887.             /*
  888.             // Support for these additional query types will come later on.
  889.             'DELETE',
  890.             'INSERT',
  891.             'REPLACE',
  892.             'TRUNCATE',
  893.             'UPDATE'
  894.             'EXPLAIN',
  895.             'DESCRIBE',
  896.             'SHOW',
  897.             'CREATE',
  898.             'SET',
  899.             'ALTER'
  900.             */
  901.         );
  902.         $supported_query_types_cnt = count($supported_query_types);
  903.  
  904.         // loop #1 for each token: select_expr, table_ref for SELECT
  905.  
  906.         for ($i = 0; $i < $size; $i++) {
  907. //DEBUG echo "trace loop1 <b>"  . $arr[$i]['data'] . "</b> (" . $arr[$i]['type'] . ")<br />";
  908.  
  909.             // High speed seek for locating the end of the current query
  910.             if ($seek_queryend == TRUE) {
  911.                 if ($arr[$i]['type'] == 'punct_queryend') {
  912.                     $seek_queryend = FALSE;
  913.                 } else {
  914.                     continue;
  915.                 } // end if (type == punct_queryend)
  916.             } // end if ($seek_queryend)
  917.  
  918.             // TODO: when we find a UNION, should we split
  919.             // in another subresult?
  920.             // Note: do not split if this is a punct_queryend for the
  921.             // first and only query
  922.             if ($arr[$i]['type'] == 'punct_queryend' && ($i + 1 != $size)) {
  923.                 $result[]  = $subresult;
  924.                 $subresult = $subresult_empty;
  925.                 continue;
  926.             } // end if (type == punct_queryend)
  927.  
  928. // ==============================================================
  929.             if ($arr[$i]['type'] == 'punct_bracket_open_round') {
  930.                 if ($in_extract) {
  931.                     $number_of_brackets_in_extract++;
  932.                 }
  933.                 if ($in_group_concat) {
  934.                     $number_of_brackets_in_group_concat++;
  935.                 }
  936.             }
  937. // ==============================================================
  938.             if ($arr[$i]['type'] == 'punct_bracket_close_round') {
  939.                 if ($in_extract) {
  940.                     $number_of_brackets_in_extract--;
  941.                     if ($number_of_brackets_in_extract == 0) {
  942.                        $in_extract = FALSE;
  943.                     }
  944.                 }
  945.                 if ($in_group_concat) {
  946.                     $number_of_brackets_in_group_concat--;
  947.                     if ($number_of_brackets_in_group_concat == 0) {
  948.                        $in_group_concat = FALSE;
  949.                     }
  950.                 }
  951.             }
  952. // ==============================================================
  953.             if ($arr[$i]['type'] == 'alpha_functionName') {
  954.                 $upper_data = strtoupper($arr[$i]['data']);
  955.                 if ($upper_data =='EXTRACT') {
  956.                     $in_extract = TRUE;
  957.                     $number_of_brackets_in_extract = 0;
  958.                 }
  959.                 if ($upper_data =='GROUP_CONCAT') {
  960.                     $in_group_concat = TRUE;
  961.                     $number_of_brackets_in_group_concat = 0;
  962.                 }
  963.             }
  964.  
  965. // ==============================================================
  966.             if ($arr[$i]['type'] == 'alpha_reservedWord'
  967. //             && $arr[$i]['forbidden'] == FALSE) {
  968.             ) {
  969.                 // We don't know what type of query yet, so run this
  970.                 if ($subresult['querytype'] == '') {
  971.                     $subresult['querytype'] = strtoupper($arr[$i]['data']);
  972.                 } // end if (querytype was empty)
  973.  
  974.                 // Check if we support this type of query
  975.                 if (!PMA_STR_binarySearchInArr($subresult['querytype'], $supported_query_types, $supported_query_types_cnt)) {
  976.                     // Skip ahead to the next one if we don't
  977.                     $seek_queryend = TRUE;
  978.                     continue;
  979.                 } // end if (query not supported)
  980.  
  981.                 // upper once
  982.                 $upper_data = strtoupper($arr[$i]['data']);
  983.                 //TODO: reset for each query?
  984.  
  985.                 if ($upper_data == 'SELECT') {
  986.                     $seen_from = FALSE;
  987.                     $previous_was_identifier = FALSE;
  988.                     $current_select_expr = -1;
  989.                     $seen_end_of_table_ref = FALSE;
  990.                 } // end if ( data == SELECT)
  991.  
  992.                 if ($upper_data =='FROM' && !$in_extract) {
  993.                     $current_table_ref = -1;
  994.                     $seen_from = TRUE;
  995.                     $previous_was_identifier = FALSE;
  996.                     $save_table_ref = TRUE;
  997.                 } // end if (data == FROM)
  998.  
  999.                 // here, do not 'continue' the loop, as we have more work for
  1000.                 // reserved words below
  1001.             } // end if (type == alpha_reservedWord)
  1002.  
  1003. // ==============================
  1004.             if ($arr[$i]['type'] == 'quote_backtick'
  1005.              || $arr[$i]['type'] == 'quote_double'
  1006.              || $arr[$i]['type'] == 'quote_single'
  1007.              || $arr[$i]['type'] == 'alpha_identifier'
  1008.              || ($arr[$i]['type'] == 'alpha_reservedWord'
  1009.                 && $arr[$i]['forbidden'] == FALSE)) {
  1010.  
  1011.                 switch ($arr[$i]['type']) {
  1012.                     case 'alpha_identifier':
  1013.                     case 'alpha_reservedWord':
  1014.                         // this is not a real reservedWord, because
  1015.                         // it's not present in the list of forbidden words,
  1016.                         // for example "storage" which can be used as
  1017.                         // an identifier
  1018.                         //
  1019.                         // TODO: avoid the pretty printing in color
  1020.                         //       in this case
  1021.  
  1022.                         $identifier = $arr[$i]['data'];
  1023.                         break;
  1024.  
  1025.                     case 'quote_backtick':
  1026.                     case 'quote_double':
  1027.                     case 'quote_single':
  1028.                         $identifier = PMA_unQuote($arr[$i]['data']);
  1029.                         break;
  1030.                 } // end switch
  1031.  
  1032.                 if ($subresult['querytype'] == 'SELECT' && !$in_group_concat) {
  1033.                     if (!$seen_from) {
  1034.                         if ($previous_was_identifier && isset($chain)) {
  1035.                             // found alias for this select_expr, save it
  1036.                             // but only if we got something in $chain
  1037.                             // (for example, SELECT COUNT(*) AS cnt
  1038.                             // puts nothing in $chain, so we avoid
  1039.                             // setting the alias)
  1040.                             $alias_for_select_expr = $identifier;
  1041.                         } else {
  1042.                             $chain[] = $identifier;
  1043.                             $previous_was_identifier = TRUE;
  1044.  
  1045.                         } // end if !$previous_was_identifier
  1046.                     } else {
  1047.                         // ($seen_from)
  1048.                         if ($save_table_ref && !$seen_end_of_table_ref) {
  1049.                             if ($previous_was_identifier) {
  1050.                                 // found alias for table ref
  1051.                                 // save it for later
  1052.                                 $alias_for_table_ref = $identifier;
  1053.                             } else {
  1054.                                 $chain[] = $identifier;
  1055.                                 $previous_was_identifier = TRUE;
  1056.  
  1057.                             } // end if ($previous_was_identifier)
  1058.                         } // end if ($save_table_ref &&!$seen_end_of_table_ref)
  1059.                     } // end if (!$seen_from)
  1060.                 } // end if (querytype SELECT)
  1061.             } // end if ( quote_backtick or double quote or alpha_identifier)
  1062.  
  1063. // ===================================
  1064.             if ($arr[$i]['type'] == 'punct_qualifier') {
  1065.                 // to be able to detect an identifier following another
  1066.                 $previous_was_identifier = FALSE;
  1067.                 continue;
  1068.             } // end if (punct_qualifier)
  1069.  
  1070.             // TODO: check if 3 identifiers following one another -> error
  1071.  
  1072.             //    s a v e    a    s e l e c t    e x p r
  1073.             // finding a list separator or FROM
  1074.             // means that we must save the current chain of identifiers
  1075.             // into a select expression
  1076.  
  1077.             // for now, we only save a select expression if it contains
  1078.             // at least one identifier, as we are interested in checking
  1079.             // the columns and table names, so in "select * from persons",
  1080.             // the "*" is not saved
  1081.  
  1082.             if (isset($chain) && !$seen_end_of_table_ref
  1083.                && (   (!$seen_from
  1084.                    && $arr[$i]['type'] == 'punct_listsep')
  1085.                   || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data == 'FROM')) ) {
  1086.                 $size_chain = count($chain);
  1087.                 $current_select_expr++;
  1088.                 $subresult['select_expr'][$current_select_expr] = array(
  1089.                   'expr' => '',
  1090.                   'alias' => '',
  1091.                   'db'   => '',
  1092.                   'table_name' => '',
  1093.                   'table_true_name' => '',
  1094.                   'column' => ''
  1095.                  );
  1096.  
  1097.                 if (isset($alias_for_select_expr) && strlen($alias_for_select_expr)) {
  1098.                     // we had found an alias for this select expression
  1099.                     $subresult['select_expr'][$current_select_expr]['alias'] = $alias_for_select_expr;
  1100.                     unset($alias_for_select_expr);
  1101.                 }
  1102.                 // there is at least a column
  1103.                 $subresult['select_expr'][$current_select_expr]['column'] = $chain[$size_chain - 1];
  1104.                 $subresult['select_expr'][$current_select_expr]['expr'] = $chain[$size_chain - 1];
  1105.  
  1106.                 // maybe a table
  1107.                 if ($size_chain > 1) {
  1108.                     $subresult['select_expr'][$current_select_expr]['table_name'] = $chain[$size_chain - 2];
  1109.                     // we assume for now that this is also the true name
  1110.                     $subresult['select_expr'][$current_select_expr]['table_true_name'] = $chain[$size_chain - 2];
  1111.                     $subresult['select_expr'][$current_select_expr]['expr']
  1112.                      = $subresult['select_expr'][$current_select_expr]['table_name']
  1113.                       . '.' . $subresult['select_expr'][$current_select_expr]['expr'];
  1114.                 } // end if ($size_chain > 1)
  1115.  
  1116.                 // maybe a db
  1117.                 if ($size_chain > 2) {
  1118.                     $subresult['select_expr'][$current_select_expr]['db'] = $chain[$size_chain - 3];
  1119.                     $subresult['select_expr'][$current_select_expr]['expr']
  1120.                      = $subresult['select_expr'][$current_select_expr]['db']
  1121.                       . '.' . $subresult['select_expr'][$current_select_expr]['expr'];
  1122.                 } // end if ($size_chain > 2)
  1123.                 unset($chain);
  1124.  
  1125.                 // TODO: explain this:
  1126.                 if (($arr[$i]['type'] == 'alpha_reservedWord')
  1127.                  && ($upper_data != 'FROM')) {
  1128.                     $previous_was_identifier = TRUE;
  1129.                 }
  1130.  
  1131.             } // end if (save a select expr)
  1132.  
  1133.  
  1134.             //======================================
  1135.             //    s a v e    a    t a b l e    r e f
  1136.             //======================================
  1137.  
  1138.             // maybe we just saw the end of table refs
  1139.             // but the last table ref has to be saved
  1140.             // or we are at the last token (TODO: there could be another
  1141.             // query after this one)
  1142.             // or we just got a reserved word
  1143.  
  1144.             if (isset($chain) && $seen_from && $save_table_ref
  1145.              && ($arr[$i]['type'] == 'punct_listsep'
  1146.                || ($arr[$i]['type'] == 'alpha_reservedWord' && $upper_data!="AS")
  1147.                || $seen_end_of_table_ref
  1148.                || $i==$size-1 )) {
  1149.  
  1150.                 $size_chain = count($chain);
  1151.                 $current_table_ref++;
  1152.                 $subresult['table_ref'][$current_table_ref] = array(
  1153.                   'expr'            => '',
  1154.                   'db'              => '',
  1155.                   'table_name'      => '',
  1156.                   'table_alias'     => '',
  1157.                   'table_true_name' => ''
  1158.                  );
  1159.                 if (isset($alias_for_table_ref) && strlen($alias_for_table_ref)) {
  1160.                     $subresult['table_ref'][$current_table_ref]['table_alias'] = $alias_for_table_ref;
  1161.                     unset($alias_for_table_ref);
  1162.                 }
  1163.                 $subresult['table_ref'][$current_table_ref]['table_name'] = $chain[$size_chain - 1];
  1164.                 // we assume for now that this is also the true name
  1165.                 $subresult['table_ref'][$current_table_ref]['table_true_name'] = $chain[$size_chain - 1];
  1166.                 $subresult['table_ref'][$current_table_ref]['expr']
  1167.                      = $subresult['table_ref'][$current_table_ref]['table_name'];
  1168.                 // maybe a db
  1169.                 if ($size_chain > 1) {
  1170.                     $subresult['table_ref'][$current_table_ref]['db'] = $chain[$size_chain - 2];
  1171.                     $subresult['table_ref'][$current_table_ref]['expr']
  1172.                      = $subresult['table_ref'][$current_table_ref]['db']
  1173.                       . '.' . $subresult['table_ref'][$current_table_ref]['expr'];
  1174.                 } // end if ($size_chain > 1)
  1175.  
  1176.                 // add the table alias into the whole expression
  1177.                 $subresult['table_ref'][$current_table_ref]['expr']
  1178.                  .= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias'];
  1179.  
  1180.                 unset($chain);
  1181.                 $previous_was_identifier = TRUE;
  1182.                 //continue;
  1183.  
  1184.             } // end if (save a table ref)
  1185.  
  1186.  
  1187.             // when we have found all table refs,
  1188.             // for each table_ref alias, put the true name of the table
  1189.             // in the corresponding select expressions
  1190.  
  1191.             if (isset($current_table_ref) && ($seen_end_of_table_ref || $i == $size-1) && $subresult != $subresult_empty) {
  1192.                 for ($tr=0; $tr <= $current_table_ref; $tr++) {
  1193.                     $alias = $subresult['table_ref'][$tr]['table_alias'];
  1194.                     $truename = $subresult['table_ref'][$tr]['table_true_name'];
  1195.                     for ($se=0; $se <= $current_select_expr; $se++) {
  1196.                         if (isset($alias) && strlen($alias) && $subresult['select_expr'][$se]['table_true_name']
  1197.                            == $alias) {
  1198.                             $subresult['select_expr'][$se]['table_true_name']
  1199.                              = $truename;
  1200.                         } // end if (found the alias)
  1201.                     } // end for (select expressions)
  1202.  
  1203.                 } // end for (table refs)
  1204.             } // end if (set the true names)
  1205.  
  1206.  
  1207.            // e n d i n g    l o o p  #1
  1208.            // set the $previous_was_identifier to FALSE if the current
  1209.            // token is not an identifier
  1210.            if (($arr[$i]['type'] != 'alpha_identifier')
  1211.             && ($arr[$i]['type'] != 'quote_double')
  1212.             && ($arr[$i]['type'] != 'quote_single')
  1213.             && ($arr[$i]['type'] != 'quote_backtick')) {
  1214.                $previous_was_identifier = FALSE;
  1215.            } // end if
  1216.  
  1217.            // however, if we are on AS, we must keep the $previous_was_identifier
  1218.            if (($arr[$i]['type'] == 'alpha_reservedWord')
  1219.             && ($upper_data == 'AS'))  {
  1220.                $previous_was_identifier = TRUE;
  1221.            }
  1222.  
  1223.            if (($arr[$i]['type'] == 'alpha_reservedWord')
  1224.             && ($upper_data =='ON' || $upper_data =='USING')) {
  1225.                $save_table_ref = FALSE;
  1226.            } // end if (data == ON)
  1227.  
  1228.            if (($arr[$i]['type'] == 'alpha_reservedWord')
  1229.             && ($upper_data =='JOIN' || $upper_data =='FROM')) {
  1230.                $save_table_ref = TRUE;
  1231.            } // end if (data == JOIN)
  1232.  
  1233.            // no need to check the end of table ref if we already did
  1234.            // TODO: maybe add "&& $seen_from"
  1235.            if (!$seen_end_of_table_ref) {
  1236.                // if this is the last token, it implies that we have
  1237.                // seen the end of table references
  1238.                // Check for the end of table references
  1239.                //
  1240.                // Note: if we are analyzing a GROUP_CONCAT clause,
  1241.                // we might find a word that seems to indicate that
  1242.                // we have found the end of table refs (like ORDER)
  1243.                // but it's a modifier of the GROUP_CONCAT so
  1244.                // it's not the real end of table refs
  1245.                if (($i == $size-1)
  1246.                  || ($arr[$i]['type'] == 'alpha_reservedWord'
  1247.                  && !$in_group_concat
  1248.                  && PMA_STR_binarySearchInArr($upper_data, $words_ending_table_ref, $words_ending_table_ref_cnt))) {
  1249.                    $seen_end_of_table_ref = TRUE;
  1250.                    // to be able to save the last table ref, but do not
  1251.                    // set it true if we found a word like "ON" that has
  1252.                    // already set it to false
  1253.                    if (isset($save_table_ref) && $save_table_ref != FALSE) {
  1254.                       $save_table_ref = TRUE;
  1255.                    } //end if
  1256.  
  1257.                } // end if (check for end of table ref)
  1258.            } //end if (!$seen_end_of_table_ref)
  1259.  
  1260.            if ($seen_end_of_table_ref) {
  1261.                $save_table_ref = FALSE;
  1262.            } // end if
  1263.  
  1264.         } // end for $i (loop #1)
  1265.  
  1266.         // -------------------------------------------------------
  1267.         // This is a big hunk of debugging code by Marc for this.
  1268.         // -------------------------------------------------------
  1269.         /*
  1270.           if (isset($current_select_expr)) {
  1271.            for ($trace=0; $trace<=$current_select_expr; $trace++) {
  1272.                echo "<br />";
  1273.                reset ($subresult['select_expr'][$trace]);
  1274.                while (list ($key, $val) = each ($subresult['select_expr'][$trace]))
  1275.                    echo "sel expr $trace $key => $val<br />\n";
  1276.                }
  1277.           }
  1278.  
  1279.           if (isset($current_table_ref)) {
  1280.            echo "current_table_ref = " . $current_table_ref . "<br>";
  1281.            for ($trace=0; $trace<=$current_table_ref; $trace++) {
  1282.  
  1283.                echo "<br />";
  1284.                reset ($subresult['table_ref'][$trace]);
  1285.                while (list ($key, $val) = each ($subresult['table_ref'][$trace]))
  1286.                echo "table ref $trace $key => $val<br />\n";
  1287.                }
  1288.           }
  1289.         */
  1290.         // -------------------------------------------------------
  1291.  
  1292.  
  1293.         // loop #2: - queryflags
  1294.         //          - querytype (for queries != 'SELECT')
  1295.         //          - section_before_limit, section_after_limit
  1296.         //
  1297.         // we will also need this queryflag in loop 2
  1298.         // so set it here
  1299.         if (isset($current_table_ref) && $current_table_ref > -1) {
  1300.             $subresult['queryflags']['select_from'] = 1;
  1301.         }
  1302.  
  1303.         $collect_section_before_limit = TRUE;
  1304.         $section_before_limit = '';
  1305.         $section_after_limit = '';
  1306.         $seen_reserved_word = FALSE;
  1307.         $seen_group = FALSE;
  1308.         $seen_order = FALSE;
  1309.         $in_group_by = FALSE; // true when we are inside the GROUP BY clause
  1310.         $in_order_by = FALSE; // true when we are inside the ORDER BY clause
  1311.         $in_having = FALSE; // true when we are inside the HAVING clause
  1312.         $in_select_expr = FALSE; // true when we are inside the select expr clause
  1313.         $in_where = FALSE; // true when we are inside the WHERE clause
  1314.         $in_from = FALSE;
  1315.         $in_group_concat = FALSE;
  1316.         $unsorted_query = '';
  1317.         $first_reserved_word = '';
  1318.         $current_identifier = '';
  1319.  
  1320.         for ($i = 0; $i < $size; $i++) {
  1321. //DEBUG echo "trace loop2 <b>"  . $arr[$i]['data'] . "</b> (" . $arr[$i]['type'] . ")<br />";
  1322.  
  1323.            // need_confirm
  1324.            //
  1325.            // check for reserved words that will have to generate
  1326.            // a confirmation request later in sql.php
  1327.            // the cases are:
  1328.            //   DROP TABLE
  1329.            //   DROP DATABASE
  1330.            //   ALTER TABLE... DROP
  1331.            //   DELETE FROM...
  1332.            //
  1333.            // this code is not used for confirmations coming from functions.js
  1334.  
  1335.            // TODO: check for punct_queryend
  1336.  
  1337.  
  1338.            // TODO: verify C-style comments?
  1339.            if ($arr[$i]['type'] == 'comment_ansi') {
  1340.                $collect_section_before_limit = FALSE;
  1341.            }
  1342.  
  1343.            if ($arr[$i]['type'] == 'alpha_reservedWord') {
  1344.                $upper_data = strtoupper($arr[$i]['data']);
  1345.                if (!$seen_reserved_word) {
  1346.                    $first_reserved_word = $upper_data;
  1347.                    $subresult['querytype'] = $upper_data;
  1348.                    $seen_reserved_word = TRUE;
  1349.  
  1350.                    // if the first reserved word is DROP or DELETE,
  1351.                    // we know this is a query that needs to be confirmed
  1352.                    if ($first_reserved_word=='DROP'
  1353.                        || $first_reserved_word == 'DELETE'
  1354.                        || $first_reserved_word == 'TRUNCATE') {
  1355.                       $subresult['queryflags']['need_confirm'] = 1;
  1356.                    }
  1357.  
  1358.                    if ($first_reserved_word=='SELECT'){
  1359.                        $position_of_first_select = $i;
  1360.                    }
  1361.  
  1362.                } else {
  1363.                    if ($upper_data=='DROP' && $first_reserved_word=='ALTER') {
  1364.                       $subresult['queryflags']['need_confirm'] = 1;
  1365.                    }
  1366.                }
  1367.  
  1368.                if ($upper_data == 'PROCEDURE') {
  1369.                    $collect_section_before_limit = FALSE;
  1370.                }
  1371.                // TODO: set also to FALSE if we find
  1372.                //      FOR UPDATE
  1373.                //      LOCK IN SHARE MODE
  1374.  
  1375.                if ($upper_data == 'SELECT') {
  1376.                    $in_select_expr = TRUE;
  1377.                    $select_expr_clause = '';
  1378.                }
  1379.                if ($upper_data == 'DISTINCT' && !$in_group_concat) {
  1380.                       $subresult['queryflags']['distinct'] = 1;
  1381.                }
  1382.  
  1383.                if ($upper_data == 'UNION') {
  1384.                       $subresult['queryflags']['union'] = 1;
  1385.                }
  1386.  
  1387.                if ($upper_data == 'JOIN') {
  1388.                       $subresult['queryflags']['join'] = 1;
  1389.                }
  1390.  
  1391.                if ($upper_data == 'OFFSET') {
  1392.                       $subresult['queryflags']['offset'] = 1;
  1393.                }
  1394.  
  1395.                // if this is a real SELECT...FROM
  1396.                if ($upper_data == 'FROM' && isset($subresult['queryflags']['select_from']) && $subresult['queryflags']['select_from'] == 1) {
  1397.                    $in_from = TRUE;
  1398.                    $from_clause = '';
  1399.                    $in_select_expr = FALSE;
  1400.                }
  1401.  
  1402.  
  1403.                // (we could have less resetting of variables to FALSE
  1404.                // if we trust that the query respects the standard
  1405.                // MySQL order for clauses)
  1406.  
  1407.                // we use $seen_group and $seen_order because we are looking
  1408.                // for the BY
  1409.                if ($upper_data == 'GROUP') {
  1410.                    $seen_group = TRUE;
  1411.                    $seen_order = FALSE;
  1412.                    $in_having = FALSE;
  1413.                    $in_order_by = FALSE;
  1414.                    $in_where = FALSE;
  1415.                    $in_select_expr = FALSE;
  1416.                    $in_from = FALSE;
  1417.                }
  1418.                if ($upper_data == 'ORDER' && !$in_group_concat) {
  1419.                    $seen_order = TRUE;
  1420.                    $seen_group = FALSE;
  1421.                    $in_having = FALSE;
  1422.                    $in_group_by = FALSE;
  1423.                    $in_where = FALSE;
  1424.                    $in_select_expr = FALSE;
  1425.                    $in_from = FALSE;
  1426.                }
  1427.                if ($upper_data == 'HAVING') {
  1428.                    $in_having = TRUE;
  1429.                    $having_clause = '';
  1430.                    $seen_group = FALSE;
  1431.                    $seen_order = FALSE;
  1432.                    $in_group_by = FALSE;
  1433.                    $in_order_by = FALSE;
  1434.                    $in_where = FALSE;
  1435.                    $in_select_expr = FALSE;
  1436.                    $in_from = FALSE;
  1437.                }
  1438.  
  1439.                if ($upper_data == 'WHERE') {
  1440.                    $in_where = TRUE;
  1441.                    $where_clause = '';
  1442.                    $where_clause_identifiers = array();
  1443.                    $seen_group = FALSE;
  1444.                    $seen_order = FALSE;
  1445.                    $in_group_by = FALSE;
  1446.                    $in_order_by = FALSE;
  1447.                    $in_having = FALSE;
  1448.                    $in_select_expr = FALSE;
  1449.                    $in_from = FALSE;
  1450.                }
  1451.  
  1452.                if ($upper_data == 'BY') {
  1453.                    if ($seen_group) {
  1454.                        $in_group_by = TRUE;
  1455.                        $group_by_clause = '';
  1456.                    }
  1457.                    if ($seen_order) {
  1458.                        $in_order_by = TRUE;
  1459.                        $order_by_clause = '';
  1460.                    }
  1461.                }
  1462.  
  1463.                // if we find one of the words that could end the clause
  1464.                if (PMA_STR_binarySearchInArr($upper_data, $words_ending_clauses, $words_ending_clauses_cnt)) {
  1465.  
  1466.                    $in_group_by = FALSE;
  1467.                    $in_order_by = FALSE;
  1468.                    $in_having   = FALSE;
  1469.                    $in_where    = FALSE;
  1470.                    $in_select_expr = FALSE;
  1471.                    $in_from = FALSE;
  1472.                }
  1473.  
  1474.            } // endif (reservedWord)
  1475.  
  1476.  
  1477.            // do not add a blank after a function name
  1478.            // TODO: can we combine loop 2 and loop 1?
  1479.            // some code is repeated here...
  1480.  
  1481.            $sep=' ';
  1482.            if ($arr[$i]['type'] == 'alpha_functionName') {
  1483.                $sep='';
  1484.                $upper_data = strtoupper($arr[$i]['data']);
  1485.                if ($upper_data =='GROUP_CONCAT') {
  1486.                    $in_group_concat = TRUE;
  1487.                    $number_of_brackets_in_group_concat = 0;
  1488.                }
  1489.            }
  1490.  
  1491.            if ($arr[$i]['type'] == 'punct_bracket_open_round') {
  1492.                if ($in_group_concat) {
  1493.                   $number_of_brackets_in_group_concat++;
  1494.                }
  1495.            }
  1496.            if ($arr[$i]['type'] == 'punct_bracket_close_round') {
  1497.                if ($in_group_concat) {
  1498.                   $number_of_brackets_in_group_concat--;
  1499.                   if ($number_of_brackets_in_group_concat == 0) {
  1500.                      $in_group_concat = FALSE;
  1501.                   }
  1502.                }
  1503.            }
  1504.  
  1505.            if ($in_select_expr && $upper_data != 'SELECT' && $upper_data != 'DISTINCT') {
  1506.                $select_expr_clause .= $arr[$i]['data'] . $sep;
  1507.            }
  1508.            if ($in_from && $upper_data != 'FROM') {
  1509.                $from_clause .= $arr[$i]['data'] . $sep;
  1510.            }
  1511.            if ($in_group_by && $upper_data != 'GROUP' && $upper_data != 'BY') {
  1512.                $group_by_clause .= $arr[$i]['data'] . $sep;
  1513.            }
  1514.            if ($in_order_by && $upper_data != 'ORDER' && $upper_data != 'BY') {
  1515.                // add a space only before ASC or DESC
  1516.                // not around the dot between dbname and tablename
  1517.                if ($arr[$i]['type'] == 'alpha_reservedWord') {
  1518.                   $order_by_clause .= $sep;
  1519.                }
  1520.                $order_by_clause .= $arr[$i]['data'];
  1521.            }
  1522.            if ($in_having && $upper_data != 'HAVING') {
  1523.                $having_clause .= $arr[$i]['data'] . $sep;
  1524.            }
  1525.            if ($in_where && $upper_data != 'WHERE') {
  1526.                $where_clause .= $arr[$i]['data'] . $sep;
  1527.  
  1528.                if (($arr[$i]['type'] == 'quote_backtick')
  1529.                 || ($arr[$i]['type'] == 'alpha_identifier')) {
  1530.                    $where_clause_identifiers[] = $arr[$i]['data'];
  1531.                }
  1532.            }
  1533.  
  1534.            if (isset($subresult['queryflags']['select_from'])
  1535.              && $subresult['queryflags']['select_from'] == 1
  1536.              && !$seen_order) {
  1537.                $unsorted_query .= $arr[$i]['data'];
  1538.  
  1539.                if ($arr[$i]['type'] != 'punct_bracket_open_round'
  1540.                && $arr[$i]['type'] != 'punct_bracket_close_round'
  1541.                && $arr[$i]['type'] != 'punct') {
  1542.                    $unsorted_query .= $sep;
  1543.                }
  1544.            }
  1545.  
  1546.            // clear $upper_data for next iteration
  1547.            $upper_data='';
  1548.  
  1549.            if ($collect_section_before_limit  && $arr[$i]['type'] != 'punct_queryend') {
  1550.                $section_before_limit .= $arr[$i]['data'] . $sep;
  1551.            } else {
  1552.                $section_after_limit .= $arr[$i]['data'] . $sep;
  1553.            }
  1554.  
  1555.  
  1556.         } // end for $i (loop #2)
  1557.  
  1558.  
  1559.         // -----------------------------------------------------
  1560.         // loop #3: foreign keys and MySQL 4.1.2+ TIMESTAMP options
  1561.         // (for now, check only the first query)
  1562.         // (for now, identifiers are assumed to be backquoted)
  1563.  
  1564.         // If we find that we are dealing with a CREATE TABLE query,
  1565.         // we look for the next punct_bracket_open_round, which
  1566.         // introduces the fields list. Then, when we find a
  1567.         // quote_backtick, it must be a field, so we put it into
  1568.         // the create_table_fields array. Even if this field is
  1569.         // not a timestamp, it will be useful when logic has been
  1570.         // added for complete field attributes analysis.
  1571.  
  1572.         $seen_foreign = FALSE;
  1573.         $seen_references = FALSE;
  1574.         $seen_constraint = FALSE;
  1575.         $foreign_key_number = -1;
  1576.         $seen_create_table = FALSE;
  1577.         $seen_create = FALSE;
  1578.         $in_create_table_fields = FALSE;
  1579.         $brackets_level = 0;
  1580.         $in_timestamp_options = FALSE;
  1581.         $seen_default = FALSE;
  1582.  
  1583.         for ($i = 0; $i < $size; $i++) {
  1584.         // DEBUG echo "<b>" . $arr[$i]['data'] . "</b> " . $arr[$i]['type'] . "<br />";
  1585.  
  1586.             if ($arr[$i]['type'] == 'alpha_reservedWord') {
  1587.                 $upper_data = strtoupper($arr[$i]['data']);
  1588.  
  1589.                 if ($upper_data == 'NOT' && $in_timestamp_options) {
  1590.                     $create_table_fields[$current_identifier]['timestamp_not_null'] = TRUE;
  1591.  
  1592.                 }
  1593.  
  1594.                 if ($upper_data == 'CREATE') {
  1595.                     $seen_create = TRUE;
  1596.                 }
  1597.  
  1598.                 if ($upper_data == 'TABLE' && $seen_create) {
  1599.                     $seen_create_table = TRUE;
  1600.                     $create_table_fields = array();
  1601.                 }
  1602.  
  1603.                 if ($upper_data == 'CURRENT_TIMESTAMP') {
  1604.                     if ($in_timestamp_options) {
  1605.                         if ($seen_default) {
  1606.                             $create_table_fields[$current_identifier]['default_current_timestamp'] = TRUE;
  1607.                         }
  1608.                     }
  1609.                 }
  1610.  
  1611.                 if ($upper_data == 'CONSTRAINT') {
  1612.                     $foreign_key_number++;
  1613.                     $seen_foreign = FALSE;
  1614.                     $seen_references = FALSE;
  1615.                     $seen_constraint = TRUE;
  1616.                 }
  1617.                 if ($upper_data == 'FOREIGN') {
  1618.                     $seen_foreign = TRUE;
  1619.                     $seen_references = FALSE;
  1620.                     $seen_constraint = FALSE;
  1621.                 }
  1622.                 if ($upper_data == 'REFERENCES') {
  1623.                     $seen_foreign = FALSE;
  1624.                     $seen_references = TRUE;
  1625.                     $seen_constraint = FALSE;
  1626.                 }
  1627.  
  1628.  
  1629.                 // Cases covered:
  1630.  
  1631.                 // [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}]
  1632.                 // [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}]
  1633.  
  1634.                 // but we set ['on_delete'] or ['on_cascade'] to
  1635.                 // CASCADE | SET_NULL | NO_ACTION | RESTRICT
  1636.  
  1637.                 // ON UPDATE CURRENT_TIMESTAMP
  1638.  
  1639.                 if ($upper_data == 'ON') {
  1640.                     if ($arr[$i+1]['type'] == 'alpha_reservedWord') {
  1641.                         $second_upper_data = strtoupper($arr[$i+1]['data']);
  1642.                         if ($second_upper_data == 'DELETE') {
  1643.                             $clause = 'on_delete';
  1644.                         }
  1645.                         if ($second_upper_data == 'UPDATE') {
  1646.                             $clause = 'on_update';
  1647.                         }
  1648.                         if (isset($clause)
  1649.                         && ($arr[$i+2]['type'] == 'alpha_reservedWord'
  1650.  
  1651.                 // ugly workaround because currently, NO is not
  1652.                 // in the list of reserved words in sqlparser.data
  1653.                 // (we got a bug report about not being able to use
  1654.                 // 'no' as an identifier)
  1655.                            || ($arr[$i+2]['type'] == 'alpha_identifier'
  1656.                               && strtoupper($arr[$i+2]['data'])=='NO') )
  1657.                           ) {
  1658.                             $third_upper_data = strtoupper($arr[$i+2]['data']);
  1659.                             if ($third_upper_data == 'CASCADE'
  1660.                             || $third_upper_data == 'RESTRICT') {
  1661.                                 $value = $third_upper_data;
  1662.                             } elseif ($third_upper_data == 'SET'
  1663.                               || $third_upper_data == 'NO') {
  1664.                                 if ($arr[$i+3]['type'] == 'alpha_reservedWord') {
  1665.                                     $value = $third_upper_data . '_' . strtoupper($arr[$i+3]['data']);
  1666.                                 }
  1667.                             } elseif ($third_upper_data == 'CURRENT_TIMESTAMP') {
  1668.                                 if ($clause == 'on_update'
  1669.                                 && $in_timestamp_options) {
  1670.                                     $create_table_fields[$current_identifier]['on_update_current_timestamp'] = TRUE;
  1671.                                     $seen_default = FALSE;
  1672.                                 }
  1673.  
  1674.                             } else {
  1675.                                 $value = '';
  1676.                             }
  1677.                             if (!empty($value)) {
  1678.                                 $foreign[$foreign_key_number][$clause] = $value;
  1679.                             }
  1680.                             unset($clause);
  1681.                         } // endif (isset($clause))
  1682.                     }
  1683.                 }
  1684.  
  1685.             } // end of reserved words analysis
  1686.  
  1687.  
  1688.             if ($arr[$i]['type'] == 'punct_bracket_open_round') {
  1689.                 $brackets_level++;
  1690.                 if ($seen_create_table && $brackets_level == 1) {
  1691.                     $in_create_table_fields = TRUE;
  1692.                 }
  1693.             }
  1694.  
  1695.  
  1696.             if ($arr[$i]['type'] == 'punct_bracket_close_round') {
  1697.                 $brackets_level--;
  1698.                 if ($seen_references) {
  1699.                     $seen_references = FALSE;
  1700.                 }
  1701.                 if ($seen_create_table && $brackets_level == 0) {
  1702.                     $in_create_table_fields = FALSE;
  1703.                 }
  1704.             }
  1705.  
  1706.             if (($arr[$i]['type'] == 'alpha_columnAttrib')) {
  1707.                 $upper_data = strtoupper($arr[$i]['data']);
  1708.                 if ($seen_create_table && $in_create_table_fields) {
  1709.                     if ($upper_data == 'DEFAULT') {
  1710.                         $seen_default = TRUE;
  1711.                     }
  1712.                 }
  1713.             }
  1714.  
  1715.             // note: the "or" part here is a workaround for a bug
  1716.             // (see FIXME-2005-10-16)
  1717.             if (($arr[$i]['type'] == 'alpha_columnType') || ($arr[$i]['type'] == 'alpha_functionName' && $seen_create_table)) {
  1718.                 $upper_data = strtoupper($arr[$i]['data']);
  1719.                 if ($seen_create_table && $in_create_table_fields && isset($current_identifier)) {
  1720.                     $create_table_fields[$current_identifier]['type'] = $upper_data;
  1721.                     if ($upper_data == 'TIMESTAMP') {
  1722.                         $in_timestamp_options = TRUE;
  1723.                     } else {
  1724.                         $in_timestamp_options = FALSE;
  1725.                     }
  1726.                 }
  1727.             }
  1728.  
  1729.  
  1730.             if ($arr[$i]['type'] == 'quote_backtick' || $arr[$i]['type'] == 'alpha_identifier') {
  1731.  
  1732.                 if ($arr[$i]['type'] == 'quote_backtick') {
  1733.                     // remove backquotes
  1734.                     $identifier = PMA_unQuote($arr[$i]['data']);
  1735.                 } else {
  1736.                     $identifier = $arr[$i]['data'];
  1737.                 }
  1738.  
  1739.                 if ($seen_create_table && $in_create_table_fields) {
  1740.                     $current_identifier = $identifier;
  1741.                     // warning: we set this one even for non TIMESTAMP type
  1742.                     $create_table_fields[$current_identifier]['timestamp_not_null'] = FALSE;
  1743.                 }
  1744.  
  1745.                 if ($seen_constraint) {
  1746.                     $foreign[$foreign_key_number]['constraint'] = $identifier;
  1747.                 }
  1748.  
  1749.                 if ($seen_foreign && $brackets_level > 0) {
  1750.                     $foreign[$foreign_key_number]['index_list'][] = $identifier;
  1751.                 }
  1752.  
  1753.                 if ($seen_references) {
  1754.                     // here, the first bracket level corresponds to the
  1755.                     // bracket of CREATE TABLE
  1756.                     // so if we are on level 2, it must be the index list
  1757.                     // of the foreign key REFERENCES
  1758.                     if ($brackets_level > 1) {
  1759.                         $foreign[$foreign_key_number]['ref_index_list'][] = $identifier;
  1760.                     } else {
  1761.                         // for MySQL 4.0.18, identifier is
  1762.                         // `table` or `db`.`table`
  1763.                         // the first pass will pick the db name
  1764.                         // the next pass will execute the else and pick the
  1765.                         // db name in $db_table[0]
  1766.                         if ($arr[$i+1]['type'] == 'punct_qualifier') {
  1767.                                 $foreign[$foreign_key_number]['ref_db_name'] = $identifier;
  1768.                         } else {
  1769.                         // for MySQL 4.0.16, identifier is
  1770.                         // `table` or `db.table`
  1771.                             $db_table = explode('.', $identifier);
  1772.                             if (isset($db_table[1])) {
  1773.                                 $foreign[$foreign_key_number]['ref_db_name'] = $db_table[0];
  1774.                                 $foreign[$foreign_key_number]['ref_table_name'] = $db_table[1];
  1775.                             } else {
  1776.                                 $foreign[$foreign_key_number]['ref_table_name'] = $db_table[0];
  1777.                             }
  1778.                         }
  1779.                     }
  1780.                 }
  1781.             }
  1782.         } // end for $i (loop #3)
  1783.  
  1784.  
  1785.         // Fill the $subresult array
  1786.  
  1787.         if (isset($create_table_fields)) {
  1788.             $subresult['create_table_fields'] = $create_table_fields;
  1789.         }
  1790.  
  1791.         if (isset($foreign)) {
  1792.             $subresult['foreign_keys'] = $foreign;
  1793.         }
  1794.  
  1795.         if (isset($select_expr_clause)) {
  1796.             $subresult['select_expr_clause'] = $select_expr_clause;
  1797.         }
  1798.         if (isset($from_clause)) {
  1799.             $subresult['from_clause'] = $from_clause;
  1800.         }
  1801.         if (isset($group_by_clause)) {
  1802.             $subresult['group_by_clause'] = $group_by_clause;
  1803.         }
  1804.         if (isset($order_by_clause)) {
  1805.             $subresult['order_by_clause'] = $order_by_clause;
  1806.         }
  1807.         if (isset($having_clause)) {
  1808.             $subresult['having_clause'] = $having_clause;
  1809.         }
  1810.         if (isset($where_clause)) {
  1811.             $subresult['where_clause'] = $where_clause;
  1812.         }
  1813.         if (isset($unsorted_query) && !empty($unsorted_query)) {
  1814.             $subresult['unsorted_query'] = $unsorted_query;
  1815.         }
  1816.         if (isset($where_clause_identifiers)) {
  1817.             $subresult['where_clause_identifiers'] = $where_clause_identifiers;
  1818.         }
  1819.  
  1820.         if (isset($position_of_first_select)) {
  1821.             $subresult['position_of_first_select'] = $position_of_first_select;
  1822.             $subresult['section_before_limit'] = $section_before_limit;
  1823.             $subresult['section_after_limit'] = $section_after_limit;
  1824.         }
  1825.  
  1826.         // They are naughty and didn't have a trailing semi-colon,
  1827.         // then still handle it properly
  1828.         if ($subresult['querytype'] != '') {
  1829.             $result[] = $subresult;
  1830.         }
  1831.         return $result;
  1832.     } // end of the "PMA_SQP_analyze()" function
  1833.  
  1834.  
  1835.     /**
  1836.      * Colorizes SQL queries html formatted
  1837.      *
  1838.      * @param  array   The SQL queries html formatted
  1839.      *
  1840.      * @return array   The colorized SQL queries
  1841.      *
  1842.      * @access public
  1843.      */
  1844.     function PMA_SQP_formatHtml_colorize($arr)
  1845.     {
  1846.         $i         = $GLOBALS['PMA_strpos']($arr['type'], '_');
  1847.         $class     = '';
  1848.         if ($i > 0) {
  1849.             $class = 'syntax_' . PMA_substr($arr['type'], 0, $i) . ' ';
  1850.         }
  1851.  
  1852.         $class     .= 'syntax_' . $arr['type'];
  1853.  
  1854.         //TODO: check why adding a "\n" after the </span> would cause extra
  1855.         //      blanks to be displayed:
  1856.         //      SELECT p . person_name
  1857.  
  1858.         return '<span class="' . $class . '">' . htmlspecialchars($arr['data']) . '</span>';
  1859.     } // end of the "PMA_SQP_formatHtml_colorize()" function
  1860.  
  1861.  
  1862.     /**
  1863.      * Formats SQL queries to html
  1864.      *
  1865.      * @param  array   The SQL queries
  1866.      * @param  string  mode
  1867.      * @param  integer starting token
  1868.      * @param  integer number of tokens to format, -1 = all
  1869.      *
  1870.      * @return string  The formatted SQL queries
  1871.      *
  1872.      * @access public
  1873.      */
  1874.     function PMA_SQP_formatHtml($arr, $mode='color', $start_token=0,
  1875.         $number_of_tokens=-1)
  1876.     {
  1877.         // then check for an array
  1878.         if (!is_array($arr)) {
  1879.             return htmlspecialchars($arr);
  1880.         }
  1881.         // first check for the SQL parser having hit an error
  1882.         if (PMA_SQP_isError()) {
  1883.             return htmlspecialchars($arr['raw']);
  1884.         }
  1885.         // else do it properly
  1886.         switch ($mode) {
  1887.             case 'color':
  1888.                 $str                                = '<span class="syntax">';
  1889.                 $html_line_break                    = '<br />';
  1890.                 break;
  1891.             case 'query_only':
  1892.                 $str                                = '';
  1893.                 $html_line_break                    = "\n";
  1894.                 break;
  1895.             case 'text':
  1896.                 $str                                = '';
  1897.                 $html_line_break                    = '<br />';
  1898.                 break;
  1899.         } // end switch
  1900.         $indent                                     = 0;
  1901.         $bracketlevel                               = 0;
  1902.         $functionlevel                              = 0;
  1903.         $infunction                                 = FALSE;
  1904.         $space_punct_listsep                        = ' ';
  1905.         $space_punct_listsep_function_name          = ' ';
  1906.         // $space_alpha_reserved_word = '<br />'."\n";
  1907.         $space_alpha_reserved_word                  = ' ';
  1908.  
  1909.         $keywords_with_brackets_1before            = array(
  1910.             'INDEX',
  1911.             'KEY',
  1912.             'ON',
  1913.             'USING'
  1914.         );
  1915.         $keywords_with_brackets_1before_cnt        = 4;
  1916.  
  1917.         $keywords_with_brackets_2before            = array(
  1918.             'IGNORE',
  1919.             'INDEX',
  1920.             'INTO',
  1921.             'KEY',
  1922.             'PRIMARY',
  1923.             'PROCEDURE',
  1924.             'REFERENCES',
  1925.             'UNIQUE',
  1926.             'USE'
  1927.         );
  1928.         // $keywords_with_brackets_2before_cnt = count($keywords_with_brackets_2before);
  1929.         $keywords_with_brackets_2before_cnt        = 9;
  1930.  
  1931.         // These reserved words do NOT get a newline placed near them.
  1932.         $keywords_no_newline               = array(
  1933.             'AS',
  1934.             'ASC',
  1935.             'DESC',
  1936.             'DISTINCT',
  1937.             'HOUR',
  1938.             'INTERVAL',
  1939.             'IS',
  1940.             'LIKE',
  1941.             'NOT',
  1942.             'NULL',
  1943.             'ON',
  1944.             'REGEXP'
  1945.         );
  1946.         $keywords_no_newline_cnt           = 12;
  1947.  
  1948.         // These reserved words introduce a privilege list
  1949.         $keywords_priv_list                = array(
  1950.             'GRANT',
  1951.             'REVOKE'
  1952.         );
  1953.         $keywords_priv_list_cnt            = 2;
  1954.  
  1955.         if ($number_of_tokens == -1) {
  1956.             $arraysize = $arr['len'];
  1957.         } else {
  1958.             $arraysize = $number_of_tokens;
  1959.         }
  1960.         $typearr   = array();
  1961.         if ($arraysize >= 0) {
  1962.             $typearr[0] = '';
  1963.             $typearr[1] = '';
  1964.             $typearr[2] = '';
  1965.             //$typearr[3] = $arr[0]['type'];
  1966.             $typearr[3] = $arr[$start_token]['type'];
  1967.         }
  1968.  
  1969.         $in_priv_list = FALSE;
  1970.         for ($i = $start_token; $i < $arraysize; $i++) {
  1971. // DEBUG echo "<b>" . $arr[$i]['data'] . "</b> " . $arr[$i]['type'] . "<br />";
  1972.             $before = '';
  1973.             $after  = '';
  1974.             $indent = 0;
  1975.             // array_shift($typearr);
  1976.             /*
  1977.             0 prev2
  1978.             1 prev
  1979.             2 current
  1980.             3 next
  1981.             */
  1982.             if (($i + 1) < $arraysize) {
  1983.                 // array_push($typearr, $arr[$i + 1]['type']);
  1984.                 $typearr[4] = $arr[$i + 1]['type'];
  1985.             } else {
  1986.                 //array_push($typearr, null);
  1987.                 $typearr[4] = '';
  1988.             }
  1989.  
  1990.             for ($j=0; $j<4; $j++) {
  1991.                 $typearr[$j] = $typearr[$j + 1];
  1992.             }
  1993.  
  1994.             switch ($typearr[2]) {
  1995.                 case 'white_newline':
  1996.                     $before     = '';
  1997.                     break;
  1998.                 case 'punct_bracket_open_round':
  1999.                     $bracketlevel++;
  2000.                     $infunction = FALSE;
  2001.                     // Make sure this array is sorted!
  2002.                     if (($typearr[1] == 'alpha_functionName') || ($typearr[1] == 'alpha_columnType') || ($typearr[1] == 'punct')
  2003.                         || ($typearr[3] == 'digit_integer') || ($typearr[3] == 'digit_hex') || ($typearr[3] == 'digit_float')
  2004.                         || (($typearr[0] == 'alpha_reservedWord')
  2005.                             && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 2]['data']), $keywords_with_brackets_2before, $keywords_with_brackets_2before_cnt))
  2006.                         || (($typearr[1] == 'alpha_reservedWord')
  2007.                             && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_with_brackets_1before, $keywords_with_brackets_1before_cnt))
  2008.                         ) {
  2009.                         $functionlevel++;
  2010.                         $infunction = TRUE;
  2011.                         $after      .= ' ';
  2012.                     } else {
  2013.                         $indent++;
  2014.                         $after      .= ($mode != 'query_only' ? '<div class="syntax_indent' . $indent . '">' : ' ');
  2015.                     }
  2016.                     break;
  2017.                 case 'alpha_identifier':
  2018.                     if (($typearr[1] == 'punct_qualifier') || ($typearr[3] == 'punct_qualifier')) {
  2019.                         $after      = '';
  2020.                         $before     = '';
  2021.                     }
  2022.                     if (($typearr[3] == 'alpha_columnType') || ($typearr[3] == 'alpha_identifier')) {
  2023.                         $after      .= ' ';
  2024.                     }
  2025.                     break;
  2026.                 case 'punct_qualifier':
  2027.                     $before         = '';
  2028.                     $after          = '';
  2029.                     break;
  2030.                 case 'punct_listsep':
  2031.                     if ($infunction == TRUE) {
  2032.                         $after      .= $space_punct_listsep_function_name;
  2033.                     } else {
  2034.                         $after      .= $space_punct_listsep;
  2035.                     }
  2036.                     break;
  2037.                 case 'punct_queryend':
  2038.                     if (($typearr[3] != 'comment_mysql') && ($typearr[3] != 'comment_ansi') && $typearr[3] != 'comment_c') {
  2039.                         $after     .= $html_line_break;
  2040.                         $after     .= $html_line_break;
  2041.                     }
  2042.                     $space_punct_listsep               = ' ';
  2043.                     $space_punct_listsep_function_name = ' ';
  2044.                     $space_alpha_reserved_word         = ' ';
  2045.                     $in_priv_list                      = FALSE;
  2046.                     break;
  2047.                 case 'comment_mysql':
  2048.                 case 'comment_ansi':
  2049.                     $after         .= $html_line_break;
  2050.                     break;
  2051.                 case 'punct':
  2052.                     $before         .= ' ';
  2053.                     // workaround for
  2054.                     // select * from mytable limit 0,-1
  2055.                     // (a side effect of this workaround is that
  2056.                     // select 20 - 9
  2057.                     // becomes
  2058.                     // select 20 -9
  2059.                     // )
  2060.                     if ($typearr[3] != 'digit_integer') {
  2061.                        $after        .= ' ';
  2062.                     }
  2063.                     break;
  2064.                 case 'punct_bracket_close_round':
  2065.                     $bracketlevel--;
  2066.                     if ($infunction == TRUE) {
  2067.                         $functionlevel--;
  2068.                         $after     .= ' ';
  2069.                         $before    .= ' ';
  2070.                     } else {
  2071.                         $indent--;
  2072.                         $before    .= ($mode != 'query_only' ? '</div>' : ' ');
  2073.                     }
  2074.                     $infunction    = ($functionlevel > 0) ? TRUE : FALSE;
  2075.                     break;
  2076.                 case 'alpha_columnType':
  2077.                     if ($typearr[3] == 'alpha_columnAttrib') {
  2078.                         $after     .= ' ';
  2079.                     }
  2080.                     if ($typearr[1] == 'alpha_columnType') {
  2081.                         $before    .= ' ';
  2082.                     }
  2083.                     break;
  2084.                 case 'alpha_columnAttrib':
  2085.  
  2086.                     // ALTER TABLE tbl_name AUTO_INCREMENT = 1
  2087.                     // COLLATE LATIN1_GENERAL_CI DEFAULT
  2088.                     if ($typearr[1] == 'alpha_identifier' || $typearr[1] == 'alpha_charset') {
  2089.                         $before .= ' ';
  2090.                     }
  2091.                     if (($typearr[3] == 'alpha_columnAttrib') || ($typearr[3] == 'quote_single') || ($typearr[3] == 'digit_integer')) {
  2092.                         $after     .= ' ';
  2093.                     }
  2094.                     // workaround for
  2095.                     // AUTO_INCREMENT = 31DEFAULT_CHARSET = utf-8
  2096.  
  2097.                     if ($typearr[2] == 'alpha_columnAttrib' && $typearr[3] == 'alpha_reservedWord') {
  2098.                         $before .= ' ';
  2099.                     }
  2100.                     // workaround for
  2101.                     // select * from mysql.user where binary user="root"
  2102.                     // binary is marked as alpha_columnAttrib
  2103.                     // but should be marked as a reserved word
  2104.                     if (strtoupper($arr[$i]['data']) == 'BINARY'
  2105.                       && $typearr[3] == 'alpha_identifier') {
  2106.                         $after     .= ' ';
  2107.                     }
  2108.                     break;
  2109.                 case 'alpha_reservedWord':
  2110.                     // do not uppercase the reserved word if we are calling
  2111.                     // this function in query_only mode, because we need
  2112.                     // the original query (otherwise we get problems with
  2113.                     // semi-reserved words like "storage" which is legal
  2114.                     // as an identifier name)
  2115.  
  2116.                     if ($mode != 'query_only') {
  2117.                         $arr[$i]['data'] = strtoupper($arr[$i]['data']);
  2118.                     }
  2119.  
  2120.                     if ((($typearr[1] != 'alpha_reservedWord')
  2121.                         || (($typearr[1] == 'alpha_reservedWord')
  2122.                             && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_no_newline, $keywords_no_newline_cnt)))
  2123.                         && ($typearr[1] != 'punct_level_plus')
  2124.                         && (!PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_no_newline, $keywords_no_newline_cnt))) {
  2125.                         // do not put a space before the first token, because
  2126.                         // we use a lot of eregi() checking for the first
  2127.                         // reserved word at beginning of query
  2128.                         // so do not put a newline before
  2129.                         //
  2130.                         // also we must not be inside a privilege list
  2131.                         if ($i > 0) {
  2132.                             // the alpha_identifier exception is there to
  2133.                             // catch cases like
  2134.                             // GRANT SELECT ON mydb.mytable TO myuser@localhost
  2135.                             // (else, we get mydb.mytableTO )
  2136.                             //
  2137.                             // the quote_single exception is there to
  2138.                             // catch cases like
  2139.                             // GRANT ... TO 'marc'@'domain.com' IDENTIFIED...
  2140.                             //
  2141.                             // TODO: fix all cases and find why this happens
  2142.  
  2143.                             if (!$in_priv_list || $typearr[1] == 'alpha_identifier' || $typearr[1] == 'quote_single' || $typearr[1] == 'white_newline') {
  2144.                                 $before    .= $space_alpha_reserved_word;
  2145.                             }
  2146.                         } else {
  2147.                         // on first keyword, check if it introduces a
  2148.                         // privilege list
  2149.                             if (PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_priv_list, $keywords_priv_list_cnt)) {
  2150.                                 $in_priv_list = TRUE;
  2151.                             }
  2152.                         }
  2153.                     } else {
  2154.                         $before    .= ' ';
  2155.                     }
  2156.  
  2157.                     switch ($arr[$i]['data']) {
  2158.                         case 'CREATE':
  2159.                             if (!$in_priv_list) {
  2160.                                 $space_punct_listsep       = $html_line_break;
  2161.                                 $space_alpha_reserved_word = ' ';
  2162.                             }
  2163.                             break;
  2164.                         case 'EXPLAIN':
  2165.                         case 'DESCRIBE':
  2166.                         case 'SET':
  2167.                         case 'ALTER':
  2168.                         case 'DELETE':
  2169.                         case 'SHOW':
  2170.                         case 'DROP':
  2171.                         case 'UPDATE':
  2172.                         case 'TRUNCATE':
  2173.                         case 'ANALYZE':
  2174.                         case 'ANALYSE':
  2175.                             if (!$in_priv_list) {
  2176.                                 $space_punct_listsep       = $html_line_break;
  2177.                                 $space_alpha_reserved_word = ' ';
  2178.                             }
  2179.                             break;
  2180.                         case 'INSERT':
  2181.                         case 'REPLACE':
  2182.                             if (!$in_priv_list) {
  2183.                                 $space_punct_listsep       = $html_line_break;
  2184.                                 $space_alpha_reserved_word = $html_line_break;
  2185.                             }
  2186.                             break;
  2187.                         case 'VALUES':
  2188.                             $space_punct_listsep       = ' ';
  2189.                             $space_alpha_reserved_word = $html_line_break;
  2190.                             break;
  2191.                         case 'SELECT':
  2192.                             $space_punct_listsep       = ' ';
  2193.                             $space_alpha_reserved_word = $html_line_break;
  2194.                             break;
  2195.                         default:
  2196.                             break;
  2197.                     } // end switch ($arr[$i]['data'])
  2198.  
  2199.                     $after         .= ' ';
  2200.                     break;
  2201.                 case 'digit_integer':
  2202.                 case 'digit_float':
  2203.                 case 'digit_hex':
  2204.                     //TODO: could there be other types preceding a digit?
  2205.                     if ($typearr[1] == 'alpha_reservedWord') {
  2206.                         $after .= ' ';
  2207.                     }
  2208.                     if ($infunction && $typearr[3] == 'punct_bracket_close_round') {
  2209.                         $after     .= ' ';
  2210.                     }
  2211.                     if ($typearr[1] == 'alpha_columnAttrib') {
  2212.                         $before .= ' ';
  2213.                     }
  2214.                     break;
  2215.                 case 'alpha_variable':
  2216.                     // other workaround for a problem similar to the one
  2217.                     // explained below for quote_single
  2218.                     if (!$in_priv_list && $typearr[3] != 'quote_backtick') {
  2219.                         $after      = ' ';
  2220.                     }
  2221.                     break;
  2222.                 case 'quote_double':
  2223.                 case 'quote_single':
  2224.                     // workaround: for the query
  2225.                     // REVOKE SELECT ON `base2\_db`.* FROM 'user'@'%'
  2226.                     // the @ is incorrectly marked as alpha_variable
  2227.                     // in the parser, and here, the '%' gets a blank before,
  2228.                     // which is a syntax error
  2229.                     if ($typearr[1] !='alpha_variable') {
  2230.                         $before        .= ' ';
  2231.                     }
  2232.                     if ($infunction && $typearr[3] == 'punct_bracket_close_round') {
  2233.                         $after     .= ' ';
  2234.                     }
  2235.                     break;
  2236.                 case 'quote_backtick':
  2237.                     if ($typearr[3] != 'punct_qualifier' && $typearr[3] != 'alpha_variable') {
  2238.                         $after     .= ' ';
  2239.                     }
  2240.                     if ($typearr[1] != 'punct_qualifier' && $typearr[1] != 'alpha_variable') {
  2241.                         $before    .= ' ';
  2242.                     }
  2243.                     break;
  2244.                 default:
  2245.                     break;
  2246.             } // end switch ($typearr[2])
  2247.  
  2248. /*
  2249.             if ($typearr[3] != 'punct_qualifier') {
  2250.                 $after             .= ' ';
  2251.             }
  2252.             $after                 .= "\n";
  2253. */
  2254.             $str .= $before . ($mode=='color' ? PMA_SQP_formatHTML_colorize($arr[$i]) : $arr[$i]['data']). $after;
  2255.         } // end for
  2256.         if ($mode=='color') {
  2257.             $str .= '</span>';
  2258.         }
  2259.  
  2260.         return $str;
  2261.     } // end of the "PMA_SQP_formatHtml()" function
  2262. }
  2263.  
  2264. /**
  2265.  * Builds a CSS rule used for html formatted SQL queries
  2266.  *
  2267.  * @param  string  The class name
  2268.  * @param  string  The property name
  2269.  * @param  string  The property value
  2270.  *
  2271.  * @return string  The CSS rule
  2272.  *
  2273.  * @access public
  2274.  *
  2275.  * @see    PMA_SQP_buildCssData()
  2276.  */
  2277. function PMA_SQP_buildCssRule($classname, $property, $value)
  2278. {
  2279.     $str     = '.' . $classname . ' {';
  2280.     if ($value != '') {
  2281.         $str .= $property . ': ' . $value . ';';
  2282.     }
  2283.     $str     .= '}' . "\n";
  2284.  
  2285.     return $str;
  2286. } // end of the "PMA_SQP_buildCssRule()" function
  2287.  
  2288.  
  2289. /**
  2290.  * Builds CSS rules used for html formatted SQL queries
  2291.  *
  2292.  * @return string  The CSS rules set
  2293.  *
  2294.  * @access public
  2295.  *
  2296.  * @global array   The current PMA configuration
  2297.  *
  2298.  * @see    PMA_SQP_buildCssRule()
  2299.  */
  2300. function PMA_SQP_buildCssData()
  2301. {
  2302.     global $cfg;
  2303.  
  2304.     $css_string     = '';
  2305.     foreach ($cfg['SQP']['fmtColor'] AS $key => $col) {
  2306.         $css_string .= PMA_SQP_buildCssRule('syntax_' . $key, 'color', $col);
  2307.     }
  2308.  
  2309.     for ($i = 0; $i < 8; $i++) {
  2310.         $css_string .= PMA_SQP_buildCssRule('syntax_indent' . $i, 'margin-left', ($i * $cfg['SQP']['fmtInd']) . $cfg['SQP']['fmtIndUnit']);
  2311.     }
  2312.  
  2313.     return $css_string;
  2314. } // end of the "PMA_SQP_buildCssData()" function
  2315.  
  2316. if ( ! defined( 'PMA_MINIMUM_COMMON' ) ) {
  2317.     /**
  2318.      * Gets SQL queries with no format
  2319.      *
  2320.      * @param  array   The SQL queries list
  2321.      *
  2322.      * @return string  The SQL queries with no format
  2323.      *
  2324.      * @access public
  2325.      */
  2326.     function PMA_SQP_formatNone($arr)
  2327.     {
  2328.         $formatted_sql = htmlspecialchars($arr['raw']);
  2329.         $formatted_sql = preg_replace("@((\015\012)|(\015)|(\012)){3,}@", "\n\n", $formatted_sql);
  2330.  
  2331.         return $formatted_sql;
  2332.     } // end of the "PMA_SQP_formatNone()" function
  2333.  
  2334.  
  2335.     /**
  2336.      * Gets SQL queries in text format
  2337.      *
  2338.      * @param  array   The SQL queries list
  2339.      *
  2340.      * @return string  The SQL queries in text format
  2341.      *
  2342.      * @access public
  2343.      */
  2344.     function PMA_SQP_formatText($arr)
  2345.     {
  2346.         /**
  2347.          * TODO WRITE THIS!
  2348.          */
  2349.          return PMA_SQP_formatNone($arr);
  2350.     } // end of the "PMA_SQP_formatText()" function
  2351. } // end if: minimal common.lib needed?
  2352.  
  2353. ?>
  2354.